package prototype.phase2.ui;

import java.io.File;
import java.net.URL;
import java.util.HashMap;

import javax.swing.ImageIcon;



import jmetest.audio.TestJmexAudio;
import jmetest.input.TestThirdPersonController;
import jmetest.terrain.TestTerrain;

import com.jme.bounding.BoundingBox;
import com.jme.image.Texture;
import com.jme.input.ChaseCamera;
import com.jme.input.ThirdPersonHandler;
import com.jme.light.DirectionalLight;
import com.jme.math.FastMath;
import com.jme.math.Vector3f;
import com.jme.renderer.ColorRGBA;
import com.jme.renderer.Renderer;
import com.jme.scene.Geometry;
import com.jme.scene.Line;
import com.jme.scene.Node;
import com.jme.scene.shape.Box;
import com.jme.scene.state.CullState;
import com.jme.scene.state.FogState;
import com.jme.scene.state.LightState;
import com.jme.scene.state.TextureState;
import com.jme.system.canvas.SimpleCanvasImpl;
import com.jme.util.TextureManager;
import com.jmex.audio.AudioSystem;
import com.jmex.audio.AudioTrack;
import com.jmex.audio.AudioTrack.TrackType;
import com.jmex.audio.MusicTrackQueue.RepeatType;
import com.jmex.terrain.TerrainPage;
import com.jmex.terrain.util.FaultFractalHeightMap;
import com.jmex.terrain.util.ProceduralTextureGenerator;
import java.util.Vector;
import prototype.persistence.pojo.Position;
import prototype.runtime.federate.RuntimeUser;

public class MyControlImplementor extends SimpleCanvasImpl {

    private AudioSystem audio;
    public Node m_character;
    public Node Civilian1Node;
    public Node Civilian2Node;
    public Geometry Civilian1Geo;
    public Geometry Civilian2Geo;
    public Node sniperNode;
    public Geometry sniperGeo;
    public Node policeNode;
    public Geometry policeGeo;
    public Node terroristNode;
    public Geometry terroriesGeo;
    public ChaseCamera chaser;
    public TerrainPage page;
    public ThirdPersonHandler input;
    public long startTime;
    public Geometry target;
    RuntimeUser runtimeUser;
    ColorRGBA color = new ColorRGBA(1, 0, 0, 0.5f);
    public ColorRGBA[] colors = {color, color};
    Vector3f start = new Vector3f(-250, 25, 20);
    Vector3f end = new Vector3f(260, 25, 0);
    public Line fireLine;
    public Node fireNode;
    public boolean fireAction = false;
    public boolean lineDrawn = false;
    public int control = 0;
    public Vector3f[] points = {start, end};

    public MyControlImplementor(int width, int height) {
        super(width, height);
    }

    private void drawFire() {

        Vector<Position> vec = runtimeUser.getFireLocations();
        System.out.print(vec.get(0).getX());
        System.out.print(" ");
        System.out.print(vec.get(0).getY());
        System.out.print(" ");
        System.out.print(vec.get(0).getZ());
        System.out.print(" ");
        System.out.print(vec.get(1).getX());
        System.out.print(" ");
        System.out.print(vec.get(1).getY());
        System.out.print(" ");
        System.out.print(vec.get(1).getZ());
        System.out.println(" ");
        points[0].setX(vec.get(0).getX());
        points[0].setY(vec.get(0).getY());
        points[0].setZ(vec.get(0).getZ());
        points[1].setX(vec.get(1).getX());
        points[1].setY(vec.get(1).getY());
        points[1].setZ(vec.get(1).getZ());
        fireLine = new Line("line ", points, null, colors, null);
//fireLine.setLocalScale(20f);
        fireLine.setLineWidth(5);
//fireLine.setLocalScale(new Vector3f(1, 0.1f, 0.1f));

        fireLine.setModelBound(new BoundingBox());
        fireLine.updateModelBound();
        fireNode = new Node("line node");
        rootNode.attachChild(fireNode);
        fireNode.updateModelBound();

        fireNode.attachChild(fireLine);

        //System.out.println("line drawn");
        lineDrawn = true;
        fireAction = false;

    }

    private AudioTrack getDynamic() {
        return new DynamicAudioTrack();
    }

    private void eraseFire() {

        rootNode.detachChild(fireNode);
        lineDrawn = false;
        //System.out.println("erase line");
    }

    public void simpleSetup() {

        setupCharacter();
        setupTerrain();
        setupChaseCamera();
        setupInput();
        //setupAudio();
        setupUsers();
        if (fireAction == true && lineDrawn == false) {
            drawFire();
        }
        startTime = System.currentTimeMillis() + 5000;
    }

    private AudioTrack getMusic(URL resource) {
        // Create a non-streaming, non-looping, relative sound clip.
        AudioTrack sound = AudioSystem.getSystem().createAudioTrack(resource, true);
        sound.setType(TrackType.ENVIRONMENT);
        sound.setRelative(true);
        sound.setTargetVolume(0.7f);
        sound.setLooping(true);
        return sound;
    }

    private void setupUsers() {
        // TODO Auto-generated method stub

        Civilian1Geo = new Box("civil 1 geo", new Vector3f(), .2f, .5f, .2f);
        Civilian1Geo.setLocalScale(50f);
        Civilian1Geo.setModelBound(new BoundingBox());
        Civilian1Geo.updateModelBound();
        Civilian1Node = new Node("Civilian1Node");
        rootNode.attachChild(Civilian1Node);
        Civilian1Node.attachChild(Civilian1Geo);
        Civilian1Node.getLocalTranslation().y = 25;
        Civilian1Node.getLocalTranslation().x = 250;
        Civilian1Node.getLocalTranslation().z = 20;
        Civilian1Node.updateWorldBound();

        TextureState civil1ts = renderer.createTextureState();
        civil1ts.setEnabled(true);
        civil1ts.setTexture(
                TextureManager.loadTexture("./civil.jpg",
                Texture.MinificationFilter.BilinearNearestMipMap,
                Texture.MagnificationFilter.Bilinear));
        Civilian1Node.setRenderState(civil1ts);



        Civilian2Geo = new Box("civil 2 geo", new Vector3f(), .2f, .5f, .2f);
        Civilian2Geo.setLocalScale(50f);
        Civilian2Geo.setModelBound(new BoundingBox());
        Civilian2Geo.updateModelBound();
        Civilian2Node = new Node("Civilian2Node");
        rootNode.attachChild(Civilian2Node);
        Civilian2Node.attachChild(Civilian2Geo);
        Civilian2Node.getLocalTranslation().y = 25;
        Civilian2Node.getLocalTranslation().x = 250;
        Civilian2Node.getLocalTranslation().z = -20;
        Civilian2Node.updateWorldBound();

        TextureState civil2ts = renderer.createTextureState();
        civil2ts.setEnabled(true);
        civil2ts.setTexture(
                TextureManager.loadTexture("./civil2.jpg",
                Texture.MinificationFilter.BilinearNearestMipMap,
                Texture.MagnificationFilter.Bilinear));
        Civilian2Node.setRenderState(civil2ts);


        terroriesGeo = new Box("terrorist 2 geo", new Vector3f(), .2f, .5f, .2f);
        terroriesGeo.setLocalScale(50f);
        terroriesGeo.setModelBound(new BoundingBox());
        terroriesGeo.updateModelBound();
        terroristNode = new Node("terroristNode");
        rootNode.attachChild(terroristNode);
        terroristNode.attachChild(terroriesGeo);
        terroristNode.getLocalTranslation().y = 25;
        terroristNode.getLocalTranslation().x = 260;
        terroristNode.getLocalTranslation().z = 0;
        terroristNode.updateWorldBound();

        TextureState terroristts = renderer.createTextureState();
        terroristts.setEnabled(true);
        terroristts.setTexture(
                TextureManager.loadTexture("./terrorist.jpg",
                Texture.MinificationFilter.BilinearNearestMipMap,
                Texture.MagnificationFilter.Bilinear));
        terroristNode.setRenderState(terroristts);




        sniperGeo = new Box("sniper 2 geo", new Vector3f(), .2f, .5f, .2f);
        sniperGeo.setLocalScale(50f);
        sniperGeo.setModelBound(new BoundingBox());
        sniperGeo.updateModelBound();
        sniperNode = new Node("sniperNode");
        rootNode.attachChild(sniperNode);
        sniperNode.attachChild(sniperGeo);
        sniperNode.getLocalTranslation().y = 25;
        sniperNode.getLocalTranslation().x = -250;
        sniperNode.getLocalTranslation().z = 20;
        sniperNode.updateWorldBound();

        TextureState sniperts = renderer.createTextureState();
        sniperts.setEnabled(true);
        sniperts.setTexture(
                TextureManager.loadTexture("./sniper2.jpg",
                Texture.MinificationFilter.BilinearNearestMipMap,
                Texture.MagnificationFilter.Bilinear));
        sniperNode.setRenderState(sniperts);







        policeGeo = new Box("police geo", new Vector3f(), .2f, .5f, .2f);
        policeGeo.setLocalScale(50);
        policeGeo.setModelBound(new BoundingBox());
        policeGeo.updateModelBound();
        policeNode = new Node("policeNode");
        rootNode.attachChild(policeNode);
        policeNode.attachChild(policeGeo);
        policeNode.getLocalTranslation().y = 25;
        policeNode.getLocalTranslation().x = -250;
        policeNode.getLocalTranslation().z = -20;
        policeNode.updateWorldBound();

        TextureState policets = renderer.createTextureState();
        policets.setEnabled(true);
        policets.setTexture(
                TextureManager.loadTexture("./infantry.jpg",
                Texture.MinificationFilter.BilinearNearestMipMap,
                Texture.MagnificationFilter.Bilinear));
        policeNode.setRenderState(policets);


    }

    private void setupAudio() {
    }

    public void simpleUpdate() {

        try {
            //audio.update();
        } catch (Exception e) {
            System.out.println("my exception");
        }


        control++;

        //System.out.println(control);
        if (runtimeUser.getFireLocations().isEmpty()) {
            fireAction = false;
        } else {
            fireAction = true;
        }
        if (fireAction == true && lineDrawn == false) {
            drawFire();
        }

        if (control % 400 == 0 && lineDrawn == true) {
            control = 0;
            eraseFire();
        }


        input.update(tpf);
        chaser.update(tpf);


        if (!Vector3f.isValidVector(cam.getLocation())) {
            cam.getLocation().set(0, 0, 0);
        }

        float camMinHeight = page.getHeight(cam.getLocation()) + 2f;
        if (!Float.isInfinite(camMinHeight) && !Float.isNaN(camMinHeight)
                && cam.getLocation().y <= camMinHeight) {
            cam.getLocation().y = camMinHeight;
            cam.update();
        }

        float characterMinHeight = page.getHeight(m_character.getLocalTranslation()) + ((BoundingBox) m_character.getWorldBound()).yExtent;
        if (!Float.isInfinite(characterMinHeight) && !Float.isNaN(characterMinHeight)) {
            m_character.getLocalTranslation().y = characterMinHeight;
        }
        //chaser.getIdealSphereCoords().y = 5000;
//        page.getSurfaceNormal(m_character.getLocalTranslation(), normal);
//        if (normal != null)
//            m_character.rotateUpTo(normal);
        Vector<Position> fires = runtimeUser.getFireLocations();


    }

    private void setupCharacter() {
        target = new Box("box", new Vector3f(), .5f, .5f, .5f);
        target.setLocalScale(.1f);
        target.setModelBound(new BoundingBox());
        target.updateModelBound();
        m_character = new Node("char node");
        rootNode.attachChild(m_character);
        m_character.attachChild(target);
        m_character.getLocalTranslation().y = 255;
        m_character.updateWorldBound(); // We do this to allow the camera setup access to the world bound in our setup code.


    }

    private void setupTerrain() {
        rootNode.setRenderQueueMode(Renderer.QUEUE_OPAQUE);

        renderer.setBackgroundColor(
                new ColorRGBA(0.5f, 0.5f, 0.5f, 1));

        //DirectionalLight dr = new DirectionalLight();
        //dr.setEnabled(true);
        //dr.setDiffuse(new ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f));
        //dr.setAmbient(new ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f));
        //dr.setDirection(new Vector3f(0.5f, -0.5f, 0));

        CullState cs = renderer.createCullState();
        cs.setCullFace(CullState.Face.Back);
        cs.setEnabled(true);
        rootNode.setRenderState(cs);

        LightState lightState = renderer.createLightState();
        lightState.setEnabled(true);
        //lightState.attach(dr);
        rootNode.setRenderState(lightState);

        FaultFractalHeightMap heightMap = new FaultFractalHeightMap(257, 32, 0,
                255, 0.75f);
        Vector3f terrainScale = new Vector3f(10, 0, 10);
        heightMap.setHeightScale(0.001f);
        page = new TerrainPage("Terrain", 33, heightMap.getSize(),
                terrainScale, heightMap.getHeightMap());

        page.setDetailTexture(1, 16);
        rootNode.attachChild(page);

        ProceduralTextureGenerator pt = new ProceduralTextureGenerator(
                heightMap);
        pt.addTexture(new ImageIcon(TestTerrain.class.getClassLoader().getResource("jmetest/data/texture/grassb.png")), -128, 0, 128);
        pt.addTexture(new ImageIcon(TestTerrain.class.getClassLoader().getResource("jmetest/data/texture/dirt.jpg")), 0, 128, 255);
        pt.addTexture(new ImageIcon(TestTerrain.class.getClassLoader().getResource("jmetest/data/texture/highest.jpg")), 128, 255,
                384);

        pt.createTexture(512);

        TextureState ts = renderer.createTextureState();
        ts.setEnabled(true);
        Texture t1 = TextureManager.loadTexture(pt.getImageIcon().getImage(),
                Texture.MinificationFilter.Trilinear, Texture.MagnificationFilter.Bilinear, true);
        ts.setTexture(t1, 0);

        Texture t2 = TextureManager.loadTexture(TestThirdPersonController.class.getClassLoader().getResource("jmetest/data/texture/Detail.jpg"),
                Texture.MinificationFilter.Trilinear, Texture.MagnificationFilter.Bilinear);
        ts.setTexture(t2, 1);
        t2.setWrap(Texture.WrapMode.Repeat);

        t1.setApply(Texture.ApplyMode.Combine);
        t1.setCombineFuncRGB(Texture.CombinerFunctionRGB.Modulate);
        t1.setCombineSrc0RGB(Texture.CombinerSource.CurrentTexture);
        t1.setCombineOp0RGB(Texture.CombinerOperandRGB.SourceColor);
        t1.setCombineSrc1RGB(Texture.CombinerSource.PrimaryColor);
        t1.setCombineOp1RGB(Texture.CombinerOperandRGB.SourceColor);

        t2.setApply(Texture.ApplyMode.Combine);
        t2.setCombineFuncRGB(Texture.CombinerFunctionRGB.AddSigned);
        t2.setCombineSrc0RGB(Texture.CombinerSource.CurrentTexture);
        t2.setCombineOp0RGB(Texture.CombinerOperandRGB.SourceColor);
        t2.setCombineSrc1RGB(Texture.CombinerSource.Previous);
        t2.setCombineOp1RGB(Texture.CombinerOperandRGB.SourceColor);
        rootNode.setRenderState(ts);

        FogState fs = renderer.createFogState();
        fs.setDensity(0.1f);
        fs.setEnabled(true);
        fs.setColor(new ColorRGBA(0.5f, 0.5f, 0.5f, 0.5f));
        fs.setEnd(1000);
        fs.setStart(500);
        fs.setDensityFunction(FogState.DensityFunction.Linear);
        fs.setQuality(FogState.Quality.PerVertex);
        rootNode.setRenderState(fs);
    }

    private void setupChaseCamera() {
        Vector3f targetOffset = new Vector3f();
        targetOffset.y = ((BoundingBox) m_character.getWorldBound()).yExtent * 1.5f;

        float camMinHeight = page.getHeight(cam.getLocation()) + 2f;
        if (!Float.isInfinite(camMinHeight) && !Float.isNaN(camMinHeight)
                && cam.getLocation().y <= camMinHeight) {
            cam.getLocation().y = camMinHeight;
            cam.update();
        }

        chaser = new ChaseCamera(cam, m_character);
        chaser.setTargetOffset(targetOffset);


        // mouse kapatmak için
        chaser.getMouseLook().setEnabled(false);
        chaser.getIdealSphereCoords().z = FastMath.DEG_TO_RAD * 30;
        chaser.getIdealSphereCoords().x = 400;
        //chaser.getIdealSphereCoords().y = 5000;

    }

    private void setupInput() {
        HashMap<String, Object> handlerProps = new HashMap<String, Object>();
        handlerProps.put(ThirdPersonHandler.PROP_DOGRADUAL, "true");
        handlerProps.put(ThirdPersonHandler.PROP_TURNSPEED, "" + (1.0f * FastMath.PI));
        handlerProps.put(ThirdPersonHandler.PROP_LOCKBACKWARDS, "false");
        handlerProps.put(ThirdPersonHandler.PROP_CAMERAALIGNEDMOVE, "true");
        input = new ThirdPersonHandler(m_character, cam, handlerProps);
        input.setActionSpeed(200f);
    }
}
